#!/bin/bash

# pim_gather
#
# store data for running processes that should be monitored (configuration file)
# data will be used to notify users of long-running processes and 
# a script to kill these processes if no longer important to their user
# side-effects could be that memory statistics can be produced from the stored information
#
#    (c) 2011 Donders Centre/Simon Oosthoek
#
#    This file is part of PIM.
#
#    PIM is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 2 of the License, or
#    (at your option) any later version.
#
#    PIM is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with PIM.  If not, see <http://www.gnu.org/licenses/>.
#
# source pim_lib library (functions and settings)
. $(dirname $0)/pim_lib


# since we're running on multiple machines using a single cron entry, it's good to
# vary the starting time for a bit
if [ "x$1" != "xnosleep" ]
then
	# sleep for maximally 600 seconds
	randomsleep 300
fi

# temporary process listing
pim_psfile=/tmp/$PROG-$MACHINE-$$



# example cleanup function
function cleanup()
{
	# remove temporary process listing
	rm -f $pim_psfile
}


# from all current processes, list the...
#   user    username
#   pid     process id
#   pcpu    cpu percentage
#   vsize   virtual memory size (in KiB)
#   etime   elapsed time 
#   cmd     command with all its arguments
ps -e -o user,pid,pcpu,vsize,etime,cmd= >$pim_psfile
# bradaa                              ^-- die = ?
# simoos			      ^ no header will be printed

# read configuration file(s)
for configf in $pim_configdir/${pim_configprefix}*
do
	# bradaa: maybe read in a default config first. so we can handle missing settings.
	if [ -f $configf ]
	then
		. $configf
	else
		continue
	fi
	
	# extract process variables from the currently loaded configuration
	grep -E -- "$procgrep" $pim_psfile | while read user pid pcpu vsize etime cmdline
	do
		# a pid file will be created or updated if the process matches the current configuration
		
		# pidfile for this process
		pidfile=$pim_datadir/${MACHINE}_${pid}
		shortcmd=$(echo $cmdline|awk '{print $1}')
		
		# skip handling this process when it doesn't exist anymore
		if [ ! -f  /proc/$pid/stat ]
		then
			continue
		fi
		
		# only handle users_ignore when it is configured for this process class
		if [ -n "$users_ignore" ]
		then
			shouldignore=$(echo "$user" | awk -vignore="$users_ignore" '$0 ~ ignore {print "ignore"}' )
			if [ "x$shouldignore" = "xignore" ]
			then
				#echo "ignored: $pid, $user, $cmdline"
				continue
			fi
		fi
		
		# convert etime to seconds
		etime_secs=$(etime2sec "$etime")
		
		# calculate start time ( = now - etime)
		pid_starttime=$(($EPOCHNOW-$etime_secs))
		pid_starttime_human="$(epoch2date $pid_starttime)"
		pid_timestamp_human="$(epoch2date $EPOCHNOW)"
		
		
		# should we create a header first?
		if [ ! -f  $pidfile ]
		then
			pid_ownername="$(finger $user |sed -n '/Login.*Name: \(.*\)$/s//\1/p')"
			
			# create headerdatafile in "shell var" format:
			cat >$pidfile <<-EOPIDDATA
				pid_firstseen="$EPOCHNOW"
				pid_starttime="$pid_starttime"
				pid_starttime_human="$pid_starttime_human"
				pid_owner="$user"
				pid_ownername="$pid_ownername"
				pid_pid="$pid"
				pid_machine="$MACHINE"
				pid_memsize="$MEMSIZE"
				pid_cmdline="$cmdline"
				pid_configused="$configf"
				
			EOPIDDATA
		fi
		
		# append to datafile:
		cat >>$pidfile <<-EOPIDDATA
			pid_timestamp="$EPOCHNOW"
			pid_timestamp_human="$pid_timestamp_human"
			pid_elapsedtime="$etime"
			pid_pcpu="$pcpu"
			pid_vsize="$vsize"
		EOPIDDATA
		
		# for the web-ui store an empty file containing the username machine and pid
		> $pim_datadir/${user}_${MACHINE}_$pid
	done
done



# Cleaning up
# ==============================================================================
# check all pidfiles for actually running processes
# (re)move pidfiles that no longer exist as process
for f in $pim_datadir/$MACHINE*
do
	if [ ! -f "$f" ]
	then
		# probably no files exist for this machine
		continue
	fi
	pid_notified="0" #reset variable
	. "$f"
	if ps -p $pid_pid -o pid= -o cmd= &>/dev/null
	then
		#process is still running
		continue
	else
		# only keep processes that have seen action
		if [ $pid_notified -gt 0 ]
		then
			echo "pid_gone=\"$EPOCHNOW\"" >>$f
			echo "pid_gone_human=\"$(epoch2date $EPOCHNOW)\"" >>$f
			quiet_mv "$f" "$pim_olddatadir"
		else
			quiet_rm "$f"
		fi
		
		# remove empty files referring to this pidfile
		reffile="$pim_datadir/${pid_owner}_${pid_machine}_${pid_pid}"
		quiet_rm "$reffile" 
		
		# remove any action files related to the ex-process
		actionfile="$pim_useract/$(basename $f)"
		quiet_mv -f $actionfile $pim_olddatadir/$(basename $f)_action
	fi
done


# check for dangling empty files for users
for f in $pim_datadir/*_${MACHINE}_*
do
	if [ ! -f "$f" ]
	then
		# probably no files exist for this machine
		continue
	fi
	
	# extract pid from the filename
	pid=$(basename $f |sed 's/^.*_.*_\(.*\)$/\1/')
	
	# does the process still exist?
	if ps -p $pid -o pid= -o cmd= &>/dev/null
	then
		continue
	else
		# remove empty files referring to this pidfile
		quiet_rm "$f" 
	fi
done
	
cleanup

exit 0
